/*
 * ServletContextStringTemplateGroupLoader.java
 *
 * Copyright 2010 Jack Leow
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package my.edu.clhs.stringtemplate.servlet;

import org.antlr.stringtemplate.PathGroupLoader;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.language.DefaultTemplateLexer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;

/**
 * {@link org.antlr.stringtemplate.StringTemplateGroupLoader} implementation
 * that loads {@link org.antlr.stringtemplate.StringTemplateGroup}s from a
 * Java EE web application Servlet context.
 *
 * Note that this class depends on undocumented {@link PathGroupLoader}
 * implementation details that may change in the future.
 *
 * @author Jack Leow
 * @version 1.0
 * @since 1.0 (Feb 20, 2010, 10:55:06 PM)
 */
public class ServletContextStringTemplateGroupLoader extends PathGroupLoader {
    public static final String DEFAULT_TEMPLATE_ROOT_PATH = "/";
    
    private static final Logger log =
        LoggerFactory.getLogger(ServletContextStringTemplateGroup.class);
    
    private final ServletContext servletContext;
    
    /**
     * Creates a new <tt>ServletContextStringTemplateGroupLoader</tt> with the
     * specified template root path(s) and {@link ServletContext} for template
     * group resolution.
     *
     * @param templateRootPaths a colon delimited list of template root paths;
     *  defaults to {@link #DEFAULT_TEMPLATE_ROOT_PATH} if <tt>null</tt>
     * @param servletContext the ServletContext for template resolution
     */
    public ServletContextStringTemplateGroupLoader(
            String templateRootPaths, ServletContext servletContext) {
        super(templateRootPaths != null ?
                templateRootPaths : DEFAULT_TEMPLATE_ROOT_PATH,
            new Slf4JErrorListener(log));
        log.debug("entering this(String,ServletContext)");
        if (servletContext == null) {
            throw new NullPointerException("servletContext cannot be null");
        }
        this.servletContext = servletContext;
        log.debug("exiting this(String,ServletContext)");
    }
    
    /**
     * Gets the list of templateRootPaths.
     *
     * Added for unit testability.
     *
     * @return a List<String> of templateRootPaths
     */
    public List getTemplateRootPaths() {
        log.debug("entering getTemplateRootPaths()");
        log.debug("exiting getTemplateRootPaths()");
        return Collections.unmodifiableList(dirs);
    }
    
    /**
     * Locates the specified file in the template root paths, relative to the
     * Servlet context root, and returns a BufferedReader for the file's
     * content.
     *
     * Note that this is an undocumented {@link PathGroupLoader} implementation
     * detail that may change in the future releases (this is unlikely however,
     * as it is modeled after
     * {@link org.antlr.stringtemplate.CommonGroupLoader}).
     *
     * @param fileName the name of the file to locate.
     * @return the file's content; or <tt>null</tt> if there is no such file.
     * @throws IOException if an I/O error occurs
     */
    // @Override
    protected BufferedReader locate(String fileName) throws IOException {
        log.debug("entering locate(String)");
        BufferedReader br = null;
        
        for (int i = 0, s = dirs.size(); i < s; ++ i) {
            String dir = (String)dirs.get(i);
            String fullFilePath = dir + "/" + fileName;
            InputStream is = servletContext.getResourceAsStream(fullFilePath);
            if ( is != null ) {
                br = new BufferedReader(getInputStreamReader(is));
                break;
            }
        }
        
        log.debug("exiting locate(String)");
        return br;
    }

    /**
     * Custom {@link StringTemplateGroup#loadGroup(String)} implementation that
     * defaults to the default ($...$) template lexer.
     */
    // @Override
    public StringTemplateGroup loadGroup(String groupName) {
        return loadGroup(groupName, DefaultTemplateLexer.class, null);
    }
    
    /**
     * Custom {@link StringTemplateGroup#loadGroup(String,StringTemplateGroup)}
     * implementation that defaults to the default ($...$) template lexer.
     */
    // @Override
    public StringTemplateGroup loadGroup(
            String groupName, StringTemplateGroup superGroup) {
        return loadGroup(groupName, DefaultTemplateLexer.class, superGroup);
    }
    
    /**
     * Custom {@link StringTemplateGroup#loadGroup(String,Class,StringTemplateGroup)}
     * implementation that defaults to the default ($...$) template lexer.
     */
    // @Override
    public StringTemplateGroup loadGroup(
            String groupName, Class lexer, StringTemplateGroup superGroup) {
        return super.loadGroup(groupName,
            lexer != null ? lexer : DefaultTemplateLexer.class,
            superGroup);
    }
}